package com.gitee.wsl.mathematics.function.scale.continuous

import com.gitee.wsl.math.Math
import com.gitee.wsl.mathematics.interpolator.Interpolate
import com.gitee.wsl.math.interpolator.uninterpolateNumber
import com.gitee.wsl.math.ticks
import com.gitee.wsl.mathematics.function.scale.ClampableScale
import com.gitee.wsl.mathematics.function.scale.StrictlyContinuous
import com.gitee.wsl.mathematics.function.scale.StrictlyContinuousDomain
import com.gitee.wsl.mathematics.function.scale.Tickable
import com.gitee.wsl.mathematics.function.scale.intervalOf

/**
 * Sequential scales are similar to continuous scales in that they map a continuous numeric input domain to a
 * continuous output range. However, unlike continuous scales, the output range of a sequential scale is fixed
 * by its InterpolatorFun and not configurable.
 *
 * These scales do not expose invert, range, rangeRound and interpolate methods.
 */
 class SequentialScale<R>(var interpolator: Interpolate<R>) :
    Tickable<Double>,
    ClampableScale,
    StrictlyContinuousDomain<Double> {

    override var domain: StrictlyContinuous<Double> = intervalOf(0.0, 1.0)

    override var clamp: Boolean = false

     operator fun invoke(domainValue: Int): R {
        return this(domainValue.toDouble())
    }

     operator fun invoke(domainValue: Double): R {
        var uninterpolatedDomain = Interpolate.uninterpolateNumber(domain.start, domain.end)(domainValue)
        if (clamp) uninterpolatedDomain = uninterpolatedDomain.coerceToDefault()
        return interpolator(uninterpolatedDomain)
    }

    override fun ticks(count: Int): List<Double> = Math.ticks(domain.start, domain.end, count)
}